/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ImportDeclaration } from 'ts-morph';
import { ITaskContext } from '../..';
import { GeneratedFileInfo, ImportScanStrategy } from '../types/ImportRewriteTypes';
import { Logger } from '../../logger/Logger';
import { PathConstants } from '../../constants';
import SerializationPathUtil from '../../utils/SerializationPathUtil';

export class ImportScanStrategyImpl implements ImportScanStrategy {
  shouldRewriteImport(
    importDeclaration: ImportDeclaration,
    currentFilePath: string,
    generatedFileInfos: GeneratedFileInfo[],
    context: ITaskContext
  ): GeneratedFileInfo | null {
    const moduleSpecifier = importDeclaration.getModuleSpecifierValue();
    const importedTypes = this.extractImportedTypes(importDeclaration);

    // 跳过类型定义文件的导入重写
    if (this.isTypeDefinitionFile(currentFilePath, generatedFileInfos)) {
      return null;
    }

    // 检查是否需要重写导入
    const matchedInfo = this.resolveModuleSpecifier(
      moduleSpecifier,
      currentFilePath,
      generatedFileInfos,
      context
    );

    if (matchedInfo) {
      // 检查导入的类型是否在生成的类列表中
      const matchedTypes = importedTypes.filter(typeName =>
        matchedInfo.classNames.has(typeName)
      );

      if (matchedTypes.length > 0) {
        return matchedInfo;
      }
    }

    return null;
  }

  /**
   * 从导出声明检查是否需要重写
   * 与导入检查逻辑相同，但导出不需要检查导出的类型
   */
  shouldRewriteExport(
    moduleSpecifier: string,
    currentFilePath: string,
    generatedFileInfos: GeneratedFileInfo[],
    context: ITaskContext
  ): GeneratedFileInfo | null {
    // 没有 moduleSpecifier 说明没有 from 子句，不需要处理
    if (!moduleSpecifier) {
      return null;
    }

    // 跳过类型定义文件的导出重写
    if (this.isTypeDefinitionFile(currentFilePath, generatedFileInfos)) {
      return null;
    }

    // 使用相同的模块定位逻辑
    return this.resolveModuleSpecifier(
      moduleSpecifier,
      currentFilePath,
      generatedFileInfos,
      context
    );
  }

  /**
   * 统一的模块定位逻辑
   * 支持相对路径导入和模块化导入（包括旧包名）
   * 复用于 import 和 export 语句
   */
  private resolveModuleSpecifier(
    moduleSpecifier: string,
    currentFilePath: string,
    generatedFileInfos: GeneratedFileInfo[],
    context: ITaskContext
  ): GeneratedFileInfo | null {
    // 1. 先尝试处理相对路径导入
    if (this.isRelativeImport(moduleSpecifier)) {
      const resolvedSourcePath = this.resolveImportPath(moduleSpecifier, currentFilePath);

      // 在生成信息中查找匹配的源文件
      for (const generatedInfo of generatedFileInfos) {
        if (this.pathMatches(resolvedSourcePath, generatedInfo.sourceFilePath)) {
          return generatedInfo;
        }
      }

      return null;
    }

    // 2. 然后尝试处理模块化导入（包括旧包名）
    return this.resolveModularImportToSourceFile(
      moduleSpecifier,
      generatedFileInfos,
      context
    );
  }

  /**
   * 从模块化导入路径反推源文件
   * 核心逻辑：不依赖包名，只匹配文件路径后缀
   *
   * 例如：
   *   导入: 'sampleentry/ets/model/Person'
   *   源文件相对路径: 'src/main/ets/model/Person'
   *   提取文件路径: 'ets/model/Person'
   *   检查后缀匹配: true ✓
   */
  private resolveModularImportToSourceFile(
    moduleSpecifier: string,
    generatedFileInfos: GeneratedFileInfo[],
    context: ITaskContext
  ): GeneratedFileInfo | null {
    // 1. 提取文件路径部分（去掉包名）
    const filePath = this.extractFilePathFromModularImport(moduleSpecifier);
    if (!filePath) {
      return null;
    }

    // 2. 遍历所有源文件，尝试匹配
    for (const info of generatedFileInfos) {
      // 获取源文件的相对路径
      const sourceFileRelativePath = context.calculateSourceRootToModuleRoot(info.sourceFilePath);

      // 移除扩展名
      const pathWithoutExtension = this.removeFileExtension(sourceFileRelativePath);

      // 统一分隔符为 /
      const normalizedSourcePath = pathWithoutExtension.replaceAll(SerializationPathUtil.sep, '/');

      // 检查是否为后缀匹配
      if (this.isPathSuffix(filePath, normalizedSourcePath)) {
        Logger.debug(`模块化导入 '${moduleSpecifier}' 匹配源文件: ${info.sourceFilePath}`);
        return info;
      }
    }

    return null;
  }

  /**
   * 从模块化导入提取文件路径部分
   *
   * 例如：
   *   'sampleentry/ets/model/Person' -> 'ets/model/Person'
   *   '@hadss/pkg/ets/model/Person' -> 'ets/model/Person'
   *   'invalid' -> null
   */
  private extractFilePathFromModularImport(moduleSpecifier: string): string | null {
    const parts = moduleSpecifier.split('/');

    if (parts.length < 2) {
      return null;
    }

    // 确定包名占几个部分
    let filePathStartIndex = 1;
    if (parts[0].startsWith('@')) {
      // 作用域包：@org/package
      filePathStartIndex = 2;
    }

    if (filePathStartIndex >= parts.length) {
      // 没有文件路径部分
      return null;
    }

    return parts.slice(filePathStartIndex).join('/');
  }

  /**
   * 检查 shortPath 是否是 fullPath 的后缀
   *
   * 例如：
   *   isPathSuffix('ets/model/Person', 'src/main/ets/model/Person') -> true
   *   isPathSuffix('model/Person', 'src/main/ets/model/Person') -> true
   *   isPathSuffix('ets/model/Person', 'src/main/ets/data/Person') -> false
   */
  private isPathSuffix(shortPath: string, fullPath: string): boolean {
    const shortParts = shortPath.split('/').filter(p => p.length > 0);
    const fullParts = fullPath.split('/').filter(p => p.length > 0);

    // 如果短路径更长，不可能是后缀
    if (shortParts.length > fullParts.length) {
      return false;
    }

    // 从后向前匹配
    const offset = fullParts.length - shortParts.length;
    for (let i = 0; i < shortParts.length; i++) {
      if (shortParts[i] !== fullParts[offset + i]) {
        return false;
      }
    }

    return true;
  }

  /**
   * 移除文件扩展名
   */
  private removeFileExtension(filePath: string): string {
    const lastDotIndex = filePath.lastIndexOf('.');
    if (lastDotIndex > 0) {
      return filePath.substring(0, lastDotIndex);
    }
    return filePath;
  }

  /**
   * 检查文件是否为类型定义文件
   * 类型定义文件是指包含 @Serializable 类且生成了序列化代码的源文件
   */
  private isTypeDefinitionFile(filePath: string, generatedFileInfos: GeneratedFileInfo[]): boolean {
    return generatedFileInfos.some(info => info.sourceFilePath === filePath);
  }

  /**
   * 检查是否为相对路径导入
   */
  private isRelativeImport(moduleSpecifier: string): boolean {
    return moduleSpecifier.startsWith('./') || moduleSpecifier.startsWith('../');
  }

  /**
   * 解析导入路径为绝对路径
   * '../model/Person' + '/project/src/main/ets/features/EntityClass.ets'
   * -> '/project/src/main/ets/model/Person.ets'
   */
  private resolveImportPath(moduleSpecifier: string, currentFilePath: string): string {
    if (this.isRelativeImport(moduleSpecifier)) {
      const currentDir = SerializationPathUtil.dirname(currentFilePath);
      const resolvedPath = SerializationPathUtil.pathResolve(currentDir, moduleSpecifier);

      // 如果没有扩展名，添加 .ets
      if (!SerializationPathUtil.extname(resolvedPath)) {
        return resolvedPath + PathConstants.ETS_EXTENSIONS;
      }
      return resolvedPath;
    }
    return moduleSpecifier;
  }

  /**
   * 路径匹配检查（处理路径标准化）
   */
  private pathMatches(resolvedPath: string, sourcePath: string): boolean {
    const normalizedResolved = SerializationPathUtil.pathResolve(resolvedPath);
    const normalizedSource = SerializationPathUtil.pathResolve(sourcePath);
    return normalizedResolved === normalizedSource;
  }

  /**
   * 从导入声明中提取导入的类型名
   */
  private extractImportedTypes(importDeclaration: ImportDeclaration): string[] {
    const importedTypes: string[] = [];

    // 处理命名导入: import { Person, User } from './model'
    const namedImports = importDeclaration.getNamedImports();
    for (const namedImport of namedImports) {
      importedTypes.push(namedImport.getName());
    }

    // 处理默认导入: import Person from './Person'
    const defaultImport = importDeclaration.getDefaultImport();
    if (defaultImport) {
      importedTypes.push(defaultImport.getText());
    }

    // 处理命名空间导入: import * as Models from './models'
    const namespaceImport = importDeclaration.getNamespaceImport();
    if (namespaceImport) {
      // 对于命名空间导入，我们暂时不处理，因为这种情况比较复杂
      Logger.warn(`跳过命名空间导入: ${namespaceImport.getText()}`);
    }

    return importedTypes;
  }
}